[CU]reg model构建篇 您所在的位置:网站首页 reg data [CU]reg model构建篇

[CU]reg model构建篇

2024-03-20 15:35| 来源: 网络整理| 查看: 265

资料来源

(1) 浅谈UVM register adapter机制 (qq.com)

(2) 《UVM cookbook》

注1:该篇文章会涉及到uvm_reg_bus_op转换为uvm_sequence_item以及uvm_sequence_item发送的细节;

注2:前门访问寄存器方式1- 使用reg model以前门方式访问寄存器时,需要adapter的参与(实现uvm_reg_item到bus_transaction的转换);

注3:前门访问寄存器方式2-直接通过bus_agent(包括bus_sequencer, bus_driver等), bus sequence, bus transaction进行;这种方式绕开了reg model;

1. uvm_reg_adapter的作用

(1) uvm_reg_adapter对于前门操作而言必不可少;

注1:将reg model集成到testbench的先决条件是:  a)register model已经准备好;   b)uvm_reg_adapter类准备好;

(2) 《uvm cookbook》中对uvm_reg_adapter作用的描述比较好,如下:

There are two parts to the register adaption layer, the first part implements the sequence based stimulus layering(即reg2bus转换) and the second part implements the analysis based update of the register model using a predictor component(即bus2reg转换);

2. uvm_reg_bus_op 1 typedef struct { 2 3 uvm_access_e kind; 4 uvm_reg_addr_t addr; 5 uvm_reg_data_t data; 6 int n_bits; 7 uvm_reg_byte_en_t byte_en; 8 uvm_status_e status; 9 10 } uvm_reg_bus_op; 3. uvm_reg_adapter派生类的实现 1 virtual class uvm_reg_adapter extends uvm_object; 2 3 function new(string name=""); 4 super.new(name); 5 endfunction 6 7 bit supports_byte_enable; 8 bit provides_responses; 9 uvm_sequence_base parent_sequence; 10 11 pure virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 12 pure virtual function void bus2reg(uvm_sequence_item bus_item,ref uvm_reg_bus_op rw); 13 14 local uvm_reg_item m_item; 15 16 virtual function uvm_reg_item get_item(); 17 return m_item; 18 endfunction 19 20 virtual function void m_set_item(uvm_reg_item item); 21 m_item = item; 22 endfunction 23 endclass

(1)定义reg2bus函数,将寄存器模型通过sequence发出的uvm_reg_bus_op型变量(register model使用的通用transaction)转换成bus_sequencer能够接受的形式(与协议相关的transaction);

(2) 定义bus2reg函数,将从总线上收集来的transaction转换成寄存器模型能够接受的形式,以便寄存器模型能够更新相应的寄存器的值.

(3) supports_byte_enable成员变量:如果bus协议支持byte enable,需要在adapter的new函数中将supports_byte_enable配为0;

(4) provides_responses成员变量:如果agent driver返回一个单独的response item(比如通过put(response)或者item_done(response)),那么provides_response就会被用于register model层决定是否wait response; provides_response被设置为1的情况下,如果driver没有回复response,会发生异常情况(详见《uvm cookbook》);

1 //示例1 2 3 class my_adapter extends uvm_reg_adapter; 4 `uvm_object_utils(my_adapter) 5 string tID=get_type_name(); 6 7 function new(string name="my_adapter"); 8 super.new(name); 9 endfunction 10 11 //uvm_reg_bus_op->bus_transaction 12 function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 13 bus_transaction tr; 14 tr=new("tr"); 15 tr.addr=rw.addr; 16 tr.bus_op=(rw.kind==UVM_READ)?BUS_RD:BUS_WR; 17 18 if(tr.bus_op==BUS_WR) tr.wr_data=rw.data; 19 return tr; 20 endfunction 21 22 //bus_transaction->uvm_reg_bus_op 23 function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 24 bus_transaction tr; 25 if(!$cast(tr,bus_item)) begin 26 `uvm_fatal(tID,"Provided bus_item is not of the correct type, expecting bus_trans action") 27 return; 28 end 29 30 rw.kind=(tr.bus_op==BUS_RD)?UVM_READ:UVM_WRITE; 31 rw.addr=tr.addr; 32 rw.byte_en='h3; 33 rw.data=(tr.bus_op==BUS_RD)?tr.rd_data:tr.wr_data; 34 rw.status=UVM_IS_OK; 35 endfunction 36 endclass 1 //示例2 2 class reg2apb_adapter extends uvm_reg_adapter; 3 `uvm_object_utils(reg2apb_adapter) 4 5 function new(string name="reg2apb_adapter"); 6 super.new(name); 7 endfunction 8 9 virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 10 apb_rw apb=apb_rw::type_id::create("apb_rw"); 11 apb.kind=(rw.kind==UVM_READ)?apb_rw::READ : apb_rw::WRITE; 12 apb.addr=rw.addr; 13 apb.data=rw.data; 14 return apb; 15 endfunction 16 17 virtual fuction void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 18 apb_rw apb; 19 if(!$cast(apb, bus_item)) begin 20 `uvm_fatal("NOT_APB_TYPE","provided bus_item is not of the correct type") 21 return; 22 end 23 24 rw.kind=apb.kind?UVM_READ:UVM_WRITE; 25 rw.addr=apb.addr; 26 rw.data=apb.data; 27 rw.status=UVM_IS_OK; 28 endfunction 29 endclass 30 31 class block_env extends uvm_env; 32 block_reg_model regmodel; 33 subblk_env subblk; 34 35 virtual function void connect_phase(uvm_phase phase); 36 ... 37 if(regmodel.get_parent==null) begin 38 reg2apb_adapter reg2apb=reg2apb_adapter::type_id::create("reg2apb",get_full_name()); 39 ... 40 end 41 endfunction 42 43 endclass 1 //示例3 2 3 class vga_ral_adapter extends uvm_reg_adapter; 4 `uvm_object_utils(vga_ral_adapter) 5 6 function new(string name=""); 7 super.new(name); 8 endfunction 9 10 virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 11 wb_transaction w_trans; 12 w_trans=wb_transaction::type_id::create("w_trans"); 13 w_trans.address=rw.addr; 14 w_trans.sel=4'hf; 15 w_trans.data=rw.data; 16 w_trans.kind=(rw.kind==UVM_READ)?wb_transaction::READ:wb_transaction::WRITE; 17 18 return w_trans; 19 endfunction 20 21 virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 22 wb_transaction trans; 23 if(!$cast(trans,bus_item)) begin 24 `uvm_fatal("BUS2REF", "Wrong type received") 25 end 26 27 rw.addr=trans.address; 28 rw.data=trans.data; 29 rw.kind=(trans.kind==wb_transaction::READ)?UVM_READ:UVM_WRITE; 30 rw.status=UVM_IS_OK; 31 endfunction 32 endclass  4. uvm_reg_adapter的具体工作过程(前门访问)

(1) 通过reg_model write/read task发寄存器读写命令;

1 uvm_status_e status; 2 bit[31:0] rdata; 3 4 env.reg_model.XXXX_REG.write(status, 32'haaaa_ffff); 5 env.reg_model.XXXX_REG.read(status, rdata);

(2)在uvm_reg::write(*) task内,会调用uvm_reg::do_write(uvm_reg_item rw) task,并最终调用uvm_reg_item.local_map.do_write task,即uvm_reg_map.do_write;

(3)在uvm_reg_map的do_write task中,会先为uvm_reg_item.parent赋值,然后调用uvm_reg_map::do_bus_write task;

1 task uvm_reg_map::do_write(uvm_reg_item rw); 2 3 uvm_sequence_base tmp_parent_seq; 4 uvm_reg_map system_map = get_root_map(); 5 uvm_reg_adapter adapter = system_map.get_adapter(); 6 uvm_sequencer_base sequencer = system_map.get_sequencer(); 7 8 if (adapter != null && adapter.parent_sequence != null) begin 9 uvm_object o; 10 uvm_sequence_base seq; 11 o = adapter.parent_sequence.clone(); 12 assert($cast(seq,o)); 13 seq.set_parent_sequence(rw.parent); 14 rw.parent = seq; 15 tmp_parent_seq = seq; 16 end 17 18 if (rw.parent == null) begin 19 rw.parent = new("default_parent_seq"); 20 tmp_parent_seq = rw.parent; 21 end 22 23 if (adapter == null) begin 24 rw.set_sequencer(sequencer); 25 rw.parent.start_item(rw,rw.prior); 26 rw.parent.finish_item(rw); 27 rw.end_event.wait_on(); 28 end 29 else begin 30 do_bus_write(rw, sequencer, adapter); 31 end 32 33 if (tmp_parent_seq != null) 34 sequencer.m_sequence_exiting(tmp_parent_seq); 35 36 endtask

(4)在uvm_reg_map::do_bus_write task中,会调用uvm_reg_adapter.reg2bus将uvm_reg_bus_op转换为uvm_sequence_item;

(5)为uvm_seq_item设置相应的sequencer(该sequencer为uvm_reg_map的sequencer),并调用uvm_reg_item.parent.start_item(uvm_seq_item)进行trans的发送;

注1:uvm_reg与uvm_reg_map的联系是通过uvm_reg_map.add_reg建立的;uvm_reg_map::add_reg函数会调用uvm_reg.add_map(this);uvm_reg.add_map(this)会将this指向的uvm_reg_map作为uvm_reg的关联数组m_maps的索引);

1 function void uvm_reg_map::add_reg(uvm_reg rg, 2 uvm_reg_addr_t offset, 3 string rights = "RW", 4 bit unmapped=0, 5 uvm_reg_frontdoor frontdoor=null); 6 7 if (m_regs_info.exists(rg)) begin 8 `uvm_error("RegModel", {"Register '",rg.get_name(), 9 "' has already been added to map '",get_name(),"'"}) 10 return; 11 end 12 13 if (rg.get_parent() != get_parent()) begin 14 `uvm_error("RegModel", 15 {"Register '",rg.get_full_name(),"' may not be added to address map '", 16 get_full_name(),"' : they are not in the same block"}) 17 return; 18 end 19 20 rg.add_map(this); 21 22 begin 23 uvm_reg_map_info info = new; 24 info.offset = offset; 25 info.rights = rights; 26 info.unmapped = unmapped; 27 info.frontdoor = frontdoor; 28 m_regs_info[rg] = info; 29 end 30 endfunction 1 function void uvm_reg::add_map(uvm_reg_map map); 2 m_maps[map] = 1; 3 endfunction

注2:uvm_reg_item与uvm_reg_map的联系是怎么建立的? uvm_reg_item.local_map是在uvm_reg::do_write调用的Xcheck_accessX内获取的; uvm_reg_item.map是在uvm_reg::write等函数内获取的);

1 function bit uvm_reg::Xcheck_accessX (input uvm_reg_item rw, 2 output uvm_reg_map_info map_info, 3 input string caller); 4 5 6 if (rw.path == UVM_DEFAULT_PATH) 7 rw.path = m_parent.get_default_path(); 8 9 if (rw.path == UVM_BACKDOOR) begin 10 if (get_backdoor() == null && !has_hdl_path()) begin 11 `uvm_warning("RegModel", 12 {"No backdoor access available for register '",get_full_name(), 13 "' . Using frontdoor instead."}) 14 rw.path = UVM_FRONTDOOR; 15 end 16 else 17 rw.map = uvm_reg_map::backdoor(); 18 end 19 20 21 if (rw.path != UVM_BACKDOOR) begin 22 23 rw.local_map = get_local_map(rw.map,caller); 24 25 if (rw.local_map == null) begin 26 `uvm_error(get_type_name(), 27 {"No transactor available to physically access register on map '", 28 rw.map.get_full_name(),"'"}) 29 rw.status = UVM_NOT_OK; 30 return 0; 31 end 32 33 map_info = rw.local_map.get_reg_map_info(this); 34 35 if (map_info.frontdoor == null && map_info.unmapped) begin 36 `uvm_error("RegModel", {"Register '",get_full_name(), 37 "' unmapped in map '", 38 (rw.map==null)? rw.local_map.get_full_name():rw.map.get_full_name(), 39 "' and does not have a user-defined frontdoor"}) 40 rw.status = UVM_NOT_OK; 41 return 0; 42 end 43 44 if (rw.map == null) 45 rw.map = rw.local_map; 46 end 47 return 1; 48 endfunction 5. uvm_reg_adapter与bus_seqr及uvm_reg_map的联系

(1)通过调用regmodel.reg_map的set_sequencer(sequencer, adapter)函数使用reg adapter;

1 //示例1 2 default_map.set_sequencer(env.bus_agt.sqr,reg_sqr_adapter); 1 //示例2 2 virtual function void connect_phase(uvm_phase phase); 3 super.connect_phase(phase); 4 reg_adapter adapter; 5 adapter=reg_adapter::type_id::create("adapter",this); 6 regmodel.default_map.set_sequence(m_agent.seqr,adapter); 7 endfunction

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有